<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>手写签名制作工具</title>
    <link href="../css/all.min.css" rel="stylesheet">
    <style>
        * {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
        }
        
        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            background-color: #fff;
            color: #333;
            line-height: 1.6;
            padding: 20px;
        }
        
        .container {
            max-width: 80%;
            margin: 0 auto;
            background-color: white;
            border-radius: 12px;
            box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
            overflow: hidden;
        }
        
        .toolbar {
            display: flex;
            flex-wrap: wrap;
            gap: 15px;
            padding: 18px;
            background: linear-gradient(135deg, #f6f7f9 0%, #eef0f3 100%);
            border-bottom: 2px solid #e5e7eb;
            justify-content: center;
        }
        
        .tool-group {
            display: flex;
            align-items: center;
            gap: 8px;
            padding: 6px 10px;
            background-color: white;
            border-radius: 8px;
            box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
        }
        
        .tool-group label {
            font-size: 14px;
            font-weight: 500;
            color: #4b5563;
        }
        
        .color-option {
            width: 24px;
            height: 24px;
            border-radius: 50%;
            cursor: pointer;
            transition: all 0.2s ease;
            border: 2px solid transparent;
        }
        
        .color-option:hover {
            transform: scale(1.1);
        }
        
        .color-option.selected {
            transform: scale(1.15);
            box-shadow: 0 0 0 2px white, 0 0 0 4px #6366f1;
        }
        
        #customColor {
            width: 28px;
            height: 28px;
            border: none;
            border-radius: 50%;
            cursor: pointer;
            background: transparent;
        }
        
        #customColor::-webkit-color-swatch {
            border-radius: 50%;
            border: none;
        }
        
        #customColor::-moz-color-swatch {
            border-radius: 50%;
            border: none;
        }
        
        #brushSize {
            width: 100px;
            height: 6px;
            -webkit-appearance: none;
            background: #e5e7eb;
            border-radius: 3px;
            outline: none;
        }
        
        #brushSize::-webkit-slider-thumb {
            -webkit-appearance: none;
            width: 16px;
            height: 16px;
            background: #6366f1;
            border-radius: 50%;
            cursor: pointer;
        }
        
        #brushSize::-moz-range-thumb {
            width: 16px;
            height: 16px;
            background: #6366f1;
            border-radius: 50%;
            cursor: pointer;
            border: none;
        }
        
        #brushSizeValue {
            min-width: 20px;
            text-align: center;
            font-size: 14px;
            color: #4b5563;
        }
        
        .btn {
            padding: 8px 16px;
            border: none;
            border-radius: 8px;
            font-size: 14px;
            font-weight: 500;
            cursor: pointer;
            transition: all 0.2s ease;
            display: flex;
            align-items: center;
            gap: 6px;
        }
        
        .btn-primary {
            background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%);
            color: white;
            box-shadow: 0 2px 5px rgba(99, 102, 241, 0.3);
        }
        
        .btn-primary:hover {
            background: linear-gradient(135deg, #5658d8 0%, #7c4dff 100%);
            transform: translateY(-1px);
            box-shadow: 0 4px 8px rgba(99, 102, 241, 0.3);
        }
        
        .btn-secondary {
            background-color: #e5e7eb;
            color: #4b5563;
        }
        
        .btn-secondary:hover {
            background-color: #d1d5db;
            transform: translateY(-1px);
        }
        
        .canvas-container {
            position: relative;
            margin: 0;
            border-bottom: 1px solid #e5e7eb;
        }
        
        #signatureCanvas {
            display: block;
            width: 100%;
            height: 300px;
            background-color: white;
            cursor: crosshair;
            touch-action: none;
        }
        
        #placeholderText {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            color: #9ca3af;
            font-size: 18px;
            pointer-events: none;
            transition: opacity 0.3s ease;
        }
        
        #placeholderText.hidden {
            opacity: 0;
        }
        
        /* Modal styles */
        .modal {
            display: none;
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(0, 0, 0, 0.5);
            z-index: 1000;
            align-items: center;
            justify-content: center;
            opacity: 0;
            transition: opacity 0.3s ease;
        }
        
        .modal.show {
            display: flex;
            opacity: 1;
        }
        
        .modal-content {
            background-color: white;
            border-radius: 12px;
            padding: 24px;
            width: 90%;
            max-width: 350px;
            box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
            position: relative;
            animation: fadeIn 0.3s ease-out;
        }
        
        .close-modal {
            position: absolute;
            top: 12px;
            right: 12px;
            font-size: 24px;
            color: #9ca3af;
            cursor: pointer;
            transition: color 0.2s ease;
        }
        
        .close-modal:hover {
            color: #6b7280;
        }
        
        .modal-message {
            margin: 20px 0;
            font-size: 16px;
            color: #4b5563;
            text-align: center;
        }
        
        @keyframes fadeIn {
            from { opacity: 0; transform: translateY(-20px); }
            to { opacity: 1; transform: translateY(0); }
        }
        
        /* Responsive adjustments */
        @media (max-width: 768px) {
            .toolbar {
                gap: 10px;
                padding: 12px;
            }
            
            .tool-group {
                padding: 5px 8px;
            }
            
            .btn {
                padding: 6px 12px;
                font-size: 13px;
            }
            
            #signatureCanvas {
                height: 250px;
            }
        }
        
        @media (max-width: 480px) {
            body {
                padding: 10px;
            }
            
            .toolbar {
                flex-direction: column;
                align-items: flex-start;
            }
            
            #signatureCanvas {
                height: 200px;
            }
        }
    </style>
</head>

<body>
    <div class="container">
        <div class="toolbar">
            <div class="tool-group">
                <label>颜色:</label>
                <div class="color-option selected" style="background-color: #000000;" data-color="#000000" aria-label="黑色"></div>
                <div class="color-option" style="background-color: #ff0000;" data-color="#ff0000" aria-label="红色"></div>
                <div class="color-option" style="background-color: #0000ff;" data-color="#0000ff" aria-label="蓝色"></div>
                <div class="color-option" style="background-color: #800080;" data-color="#800080" aria-label="紫色"></div>
                <div class="color-option" style="background-color: #FFA500;" data-color="#FFA500" aria-label="橙色"></div>
                <div class="color-option" style="background-color: #FFC0CB;" data-color="#FFC0CB" aria-label="粉色"></div>
                <input type="color" id="customColor" value="#000000">
            </div>

            <div class="tool-group">
                <label>笔触大小:</label>
                <input type="range" id="brushSize" min="1" max="20" value="2">
                <span id="brushSizeValue">2</span>
            </div>

            <button id="downloadPngBtn" class="btn btn-primary">
                <i class="fas fa-download"></i> PNG
            </button>
            <button id="downloadJpgBtn" class="btn btn-primary">
                <i class="fas fa-download"></i> JPG
            </button>
            <button id="undoBtn" class="btn btn-secondary" title="撤销上一步">
                <i class="fas fa-undo-alt"></i> 撤销
            </button>
            <button id="clearBtn" class="btn btn-secondary">
                <i class="fas fa-trash-alt"></i> 清除
            </button>
        </div>

        <div class="canvas-container">
            <canvas id="signatureCanvas"></canvas>
            <div id="placeholderText">请在此处签名</div>
        </div>
    </div>

    <!-- Modal -->
    <div id="modal" class="modal">
        <div class="modal-content">
            <span class="close-modal">&times;</span>
            <p class="modal-message" id="modal-message"></p>
        </div>
    </div>

    <script>
        document.addEventListener('DOMContentLoaded', function () {
            const canvas = document.getElementById('signatureCanvas');
            const ctx = canvas.getContext('2d');
            const clearBtn = document.getElementById('clearBtn');
            const undoBtn = document.getElementById('undoBtn');
            const downloadPngBtn = document.getElementById('downloadPngBtn');
            const downloadJpgBtn = document.getElementById('downloadJpgBtn');
            const brushSizeInput = document.getElementById('brushSize');
            const brushSizeValue = document.getElementById('brushSizeValue');
            const colorOptions = document.querySelectorAll('.color-option');
            const customColorInput = document.getElementById('customColor');
            const modal = document.getElementById('modal');
            const closeModalBtn = document.querySelector('.close-modal');
            const modalMessage = document.getElementById('modal-message');
            const placeholderText = document.getElementById('placeholderText');

            // Set canvas size
            function resizeCanvas() {
                const container = canvas.parentElement;
                canvas.width = container.clientWidth;
                canvas.height = container.clientHeight;
                initCanvas();
            }

            let isDrawing = false;
            let currentColor = '#000000';
            let currentBrushSize = 2;
            let points = [];
            let drawingHistory = [];
            let currentStep = [];

            // Initialize canvas
            function initCanvas() {
                ctx.fillStyle = 'white';
                ctx.fillRect(0, 0, canvas.width, canvas.height);
                ctx.strokeStyle = currentColor;
                ctx.lineWidth = currentBrushSize;
                ctx.lineCap = 'round';
                ctx.lineJoin = 'round';
                ctx.imageSmoothingEnabled = true;
                saveDrawingState();
            }

            // Get position
            function getPosition(e) {
                const rect = canvas.getBoundingClientRect();
                return {
                    x: (e.clientX || e.touches[0].clientX) - rect.left,
                    y: (e.clientY || e.touches[0].clientY) - rect.top,
                    time: Date.now()
                };
            }

            // Draw dot
            function drawDot(x, y) {
                ctx.beginPath();
                ctx.arc(x, y, currentBrushSize/2, 0, Math.PI * 2);
                ctx.fillStyle = currentColor;
                ctx.fill();
            }

            // Draw smooth line
            function drawSmoothLine(points) {
                const p0 = points[0];
                const p1 = points[1];
                const p2 = points[2];
                
                const cp1x = p1.x + (p2.x - p0.x) / 6;
                const cp1y = p1.y + (p2.y - p0.y) / 6;
                
                const timeDiff = p2.time - p0.time;
                const distance = Math.sqrt(Math.pow(p2.x - p0.x, 2) + Math.pow(p2.y - p0.y, 2));
                const speed = distance / Math.max(1, timeDiff);
                
                const dynamicWidth = Math.max(1, Math.min(currentBrushSize, currentBrushSize * 2 / (speed + 1)));
                
                ctx.lineWidth = dynamicWidth;
                ctx.beginPath();
                ctx.moveTo(p1.x, p1.y);
                ctx.quadraticCurveTo(cp1x, cp1y, p2.x, p2.y);
                ctx.stroke();
                
                ctx.lineWidth = currentBrushSize;
            }

            // Start drawing
            function startDrawing(e) {
                isDrawing = true;
                const pos = getPosition(e);
                points = [];
                currentStep = [];
                points.push(pos);
                currentStep.push(pos);
                drawDot(pos.x, pos.y);
                placeholderText.classList.add('hidden');
            }

            // Drawing
            function draw(e) {
                if (!isDrawing) return;
                
                const pos = getPosition(e);
                points.push(pos);
                currentStep.push(pos);
                
                if (points.length > 20) {
                    points.shift();
                }
                
                if (points.length >= 3) {
                    const lastPoints = points.slice(-3);
                    drawSmoothLine(lastPoints);
                }
            }

            // Stop drawing
            function stopDrawing() {
                if (isDrawing) {
                    isDrawing = false;
                    if (currentStep.length > 0) {
                        saveDrawingState();
                    }
                }
            }

            // Save drawing state
            function saveDrawingState() {
                const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
                drawingHistory.push(imageData);
            }

            // Undo last step
            function undoLastStep() {
                if (drawingHistory.length > 1) {
                    drawingHistory.pop();
                    const prevState = drawingHistory[drawingHistory.length - 1];
                    ctx.putImageData(prevState, 0, 0);
                    
                    if (drawingHistory.length === 1) {
                        placeholderText.classList.remove('hidden');
                    }
                } else {
                    clearCanvas();
                }
            }

            // Clear canvas
            function clearCanvas() {
                ctx.clearRect(0, 0, canvas.width, canvas.height);
                initCanvas();
                placeholderText.classList.remove('hidden');
            }

            // Check if canvas is blank
            function isCanvasBlank() {
                const blank = document.createElement('canvas');
                blank.width = canvas.width;
                blank.height = canvas.height;
                return canvas.toDataURL() === blank.toDataURL();
            }

            // Download signature
            function downloadSignature(format) {
                if (isCanvasBlank()) {
                    showModal('请先签名再下载!');
                    return;
                }

                const mimeType = format === 'png' ? 'image/png' : 'image/jpeg';
                const extension = format === 'png' ? 'png' : 'jpg';
                const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
                const dataURL = canvas.toDataURL(mimeType);

                const link = document.createElement('a');
                link.href = dataURL;
                link.download = `签名-${timestamp}.${extension}`;
                document.body.appendChild(link);
                link.click();
                document.body.removeChild(link);
            }

            // Show modal
            function showModal(message) {
                modalMessage.textContent = message;
                modal.classList.add('show');
            }

            // Close modal
            function closeModal() {
                modal.classList.remove('show');
            }

            // Event listeners
            window.addEventListener('resize', resizeCanvas);
            canvas.addEventListener('mousedown', startDrawing);
            canvas.addEventListener('mousemove', draw);
            canvas.addEventListener('mouseup', stopDrawing);
            canvas.addEventListener('mouseout', stopDrawing);

            // Touch support
            canvas.addEventListener('touchstart', function (e) {
                e.preventDefault();
                startDrawing(e.touches[0]);
            });

            canvas.addEventListener('touchmove', function (e) {
                e.preventDefault();
                draw(e.touches[0]);
            });

            canvas.addEventListener('touchend', function (e) {
                e.preventDefault();
                stopDrawing();
            });

            clearBtn.addEventListener('click', clearCanvas);
            undoBtn.addEventListener('click', undoLastStep);
            downloadPngBtn.addEventListener('click', () => downloadSignature('png'));
            downloadJpgBtn.addEventListener('click', () => downloadSignature('jpg'));

            // Brush size
            brushSizeInput.addEventListener('input', function () {
                currentBrushSize = this.value;
                brushSizeValue.textContent = currentBrushSize;
                ctx.lineWidth = currentBrushSize;
            });

            // Color selection
            colorOptions.forEach(option => {
                option.addEventListener('click', function () {
                    colorOptions.forEach(opt => opt.classList.remove('selected'));
                    this.classList.add('selected');
                    currentColor = this.getAttribute('data-color');
                    ctx.strokeStyle = currentColor;
                    customColorInput.value = currentColor;
                });
            });

            customColorInput.addEventListener('input', function () {
                currentColor = this.value;
                ctx.strokeStyle = currentColor;

                colorOptions.forEach(opt => {
                    opt.classList.remove('selected');
                    if (opt.getAttribute('data-color') === currentColor) {
                        opt.classList.add('selected');
                    }
                });
            });

            // Modal events
            closeModalBtn.addEventListener('click', closeModal);
            window.addEventListener('click', function (event) {
                if (event.target === modal) {
                    closeModal();
                }
            });

            // Initialize
            resizeCanvas();
        });
    </script>
</body>

</html>